---
title: "Creating a Basic Grid"
---

An introduction to the key concepts of AG Grid.

## Overview

In this tutorial you will:

1. [Create a basic grid](./deep-dive/#create-a-basic-grid)
1. [Load external data into the grid](./deep-dive/#load-new-data)
1. [Configure columns](./deep-dive/#configure-columns)
1. [Configure grid features](./deep-dive/#configure-the-grid)
1. [Format cell values](./deep-dive/#format-cell-values)
1. [Add custom components to cells](./deep-dive/#custom-cell-components)
1. [Hook into grid events](./deep-dive/#handle-grid-events)

Once complete, you'll have an interactive grid, with custom components and formatted data - Try it out for yourself by **sorting**, **filtering**, **resizing**, **selecting**, or **editing** data in the grid:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

## Create a Basic Grid

{% if isFramework("javascript") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Grid Options:** An object which holds all of the options for the grid, such as Row Data & Column Definitions.
1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Container:** A div that contains and defines the grid's theme & dimensions.
1) **Grid API:** Provides access to Grid API methods. Initialised when creating a new grid.

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

***
{% /if %}

{% if isFramework("react") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Container:** A div that contains the grid and defines it's theme & dimensions.
1) **Grid Component:** The `AgGridReact` component with **Row Data** and **Column Definition** props.

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

_Note: `rowData` and `columnDefs` arrays use the `useState` hook. We recommend `useState` if the data is mutable, otherwise `useMemo` is preferable. Read our [Best Practices](./react-hooks/) guide to learn more about using React hooks with AG Grid._

***
{% /if %}

{% if isFramework("angular") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Grid Component:** The `ag-grid-angular` component, with Dimensions, CSS Theme, Row Data, and Column Definition attributes

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

***
{% /if %}

{% if isFramework("vue") %}
<!-- Create a Basic Grid -->

Complete our [Quick Start](./getting-started/) (or open the example below in CodeSandbox / Plunker) to start with a basic grid, comprised of:

1) **Row Data:** The data to be displayed.
1) **Column Definition:** Defines & controls grid columns.
1) **Grid Component:** The `ag-grid-vue` component, with Dimensions, CSS Theme, Row Data, and Column Definition attributes

{% gridExampleRunner title="Basic Example" name="basic-example"  exampleHeight=220 /%}

***
{% /if %}

## Load New Data

{% if isFramework("javascript") %}
<!-- Load New Data -->

The Grid API provides a way of interacting with the grid. To update the data within the grid, we can use the `setGridOption` API. Let's test this by fetching some data and updating our grid with the response:

```jsx
fetch('https://www.ag-grid.com/example-assets/space-mission-data.json')
 .then(response => response.json())
 .then((data: any) => gridApi.setGridOption('rowData', data))
```

Now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
const gridOptions = {
 rowData: [],
 colDefs: [
   { field: "mission" },
   { field: "company" },
   { field: "location" },
   { field: "date" },
   { field: "price" },
   { field: "successful" },
   { field: "rocket" }
 ]
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

_Note: There are a large number of APIs available. See our [API Docs](./grid-api/) for an exhaustive list._

***
{% /if %}

{% if isFramework("react") %}
<!-- Load New Data -->

As `rowData` is a reactive property, any updates to its state will be reflected in the grid. Let's test this by fetching some data from an external server and updating `rowData` with the response:

```jsx
// Fetch data & update rowData state
useEffect(() => {
 fetch('https://www.ag-grid.com/example-assets/space-mission-data.json') // Fetch data from server
   .then(result => result.json()) // Convert to JSON
   .then(rowData => setRowData(rowData)); // Update state of `rowData`
}, [])
```

Now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
const GridExample = () => {
 // Row Data: The data to be displayed.
 const [rowData, setRowData] = useState([]);
 const [colDefs, setColDefs] = useState([
   { field: "mission" },
   { field: "company" },
   { field: "location" },
   { field: "date" },
   { field: "price" },
   { field: "successful" },
   { field: "rocket" }
 ]);
 // ...
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

_Note: All properties that are not tagged as 'initial' are reactive. See our [API docs](./grid-options/) for a complete list._

***
{% /if %}

{% if isFramework("angular") %}
<!-- Load New Data -->

As rowData is a managed property, any updates to its value will be reflected in the grid. Let's test this by fetching some data from an external server with [Angular's HttpClient](https://angular.dev/guide/http) and updating rowData with the response.

First we need to hook into the `gridReady` event by adding `(gridReady)="onGridReady($event)"` to the `ag-grid-angular` component:

```html
<!-- The AG Grid component, with various Grid Option properties -->
<ag-grid-angular
 style="width: 100%; height: 550px;"
 class="ag-theme-quartz-dark"
 [rowData]="rowData"
 [columnDefs]="colDefs"
 (gridReady)="onGridReady($event)"
>
</ag-grid-angular>
```

_Note: [Grid Events](./deep-dive/#grid-events) are covered in more detail later on_

And then executing a HTTP request when the onGridReady event is fired, subscribing to the result to update our rowData asynchronously:

```ts
// Load data into grid when ready
onGridReady(params: GridReadyEvent) {
 this.http
   .get<any[]>('https://www.ag-grid.com/example-assets/space-mission-data.json')
   .subscribe(data => this.rowData = data);
}
```

Finally, now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
export class AppComponent {
 // Row Data: The data to be displayed.
 rowData: IRow[] = [];
 colDefs: ColDef[] = [
   { field: "mission" },
   { field: "company" },
   { field: "location" },
   { field: "date" },
   { field: "price" },
   { field: "successful" },
   { field: "rocket" }
 ];
 // ...
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

_Note: All [Grid Option](./grid-options/) properties tagged as 'managed' are automatically updated when their value changes._

***
{% /if %}

{% if isFramework("vue") %}
<!-- Load New Data -->

As rowData is a managed property, any updates to its value will be reflected in the grid. Let's test this by fetching some data from an external server and updating rowData with the response.

```jsx
// Fetch data when the component is mounted
onMounted(async () => {
 rowData.value = await fetchData();
});

const fetchData = async () => {
 const response = await fetch('https://www.ag-grid.com/example-assets/space-mission-data.json');
 return response.json();
};
```

Now that we're loading data from an external source, we can empty our `rowData` array (which will allow the grid to display a loading spinner whilst the data is being fetched) and update our `colDefs` to match the new dataset:

```jsx
const App = {
 setup() {
   const rowData = ref([]);
   const colDefs = ref([
     { field: "mission" },
     { field: "company" },
     { field: "location" },
     { field: "date" },
     { field: "price" },
     { field: "successful" },
     { field: "rocket" }
   ]);
   // ...
 }
 // ...
}
```

When we run our application, we should see a grid with ~1,400 rows of new data, and new column headers to match:

{% gridExampleRunner title="Updating Example" name="updating-example"  exampleHeight=550 /%}

Note: All [Grid Option](./grid-options/) properties tagged as 'managed' are automatically updated when their value changes.

***
{% /if %}

## Configure Columns

{% if isFramework("javascript") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
columnDefs: [
 { field: "mission", filter: true },
 // ...
],
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

{% if isFramework("react") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
const [colDefs] = useState([
 { field: "mission", filter: true },
 // ...
]);
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

{% if isFramework("angular") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
colDefs: ColDef[] = [
 { field: "mission", filter: true },
 // ...
];
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

{% if isFramework("vue") %}
<!-- Configure Columns -->

Now that we have a basic grid with some arbitrary data, we can start to configure the grid with _**Column Properties**_.

Column Properties can be added to one or more columns to enable/disable column-specific features. Let's try this by adding the `filter: true` property to the 'mission' column:

```jsx
const colDefs = ref([
 { field: "mission", filter: true },
 // ...
];
```

We should now be able to filter the 'mission' column - you can test this by filtering for the 'Apollo' missions:

{% gridExampleRunner title="Configuring Columns Example" name="configure-columns-example"  exampleHeight=550 /%}

_Note: Column properties can be used to configure a wide-range of features; refer to our [Column Properties](./column-properties/) page for a full list of features._
{% /if %}

### Default Column Definitions

{% if isFramework("javascript") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by adding the `defaultColDef` property to our Grid Options object, and setting `filter: true`:

```jsx
const gridOptions = {
 defaultColDef: {
   filter: true
 }
 // ...
}
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_

***
{% /if %}

{% if isFramework("react") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by creating a `defaultColDef` object, setting `filter: true`, and passing this to the grid via the `defaultColDef` prop:

```jsx
// Apply settings across all columns
const defaultColDef = useMemo(() => ({
 filter: true // Enable filtering on all columns
}))

<div className="ag-theme-quartz" style={{ width: 600, height: 500 }}>
 <AgGridReact
   defaultColDef={defaultColDef}
   //...
 />
</div>
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_

***
{% /if %}

{% if isFramework("angular") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by creating a `defaultColDef` object, setting `filter: true`, and passing this to our template:

```jsx
@Component({
 template:
 `
 <div class="content">
   <ag-grid-angular
     ...
     [defaultColDef]="defaultColDef"
   >
   </ag-grid-angular>
 </div>
 `,
 // ...
})

export class AppComponent {
 // Default Column Definitions: Apply configuration across all columns
 defaultColDef: ColDef = {
   filter: true
 }
 // ...
}
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_

***
{% /if %}

{% if isFramework("vue") %}
<!-- Default Column Definitions -->

The example above demonstrates how to configure a single column. To apply this configuration across all columns we can use _**Default Column Definitions**_ instead. Let's make all of our columns filterable by creating a `defaultColDef` object with the property `filter: true`:

```jsx
const App = {
 setup() {
   const defaultColDef = ref({
     filter: true
   });
   // ...
 }
 return {
   defaultColDef
   // ...
 };
 // ...
}
```

And then adding this to our `ag-grid-vue` component:

```jsx
const App = {
 template:
   `
   <ag-grid-vue
     style="width: 100%; height: 100%"
     class="ag-theme-quartz-dark"
     :columnDefs="colDefs"
     :rowData="rowData"
     :defaultColDef="defaultColDef"
   >
   </ag-grid-vue>
   `,
 // ...
}
```

The grid should now allow filtering on all columns:

{% gridExampleRunner title="Default Column Definitions Example" name="default-columns-example"  exampleHeight=550 /%}

_Note: Column Definitions take precedence over Default Column Definitions_

***
{% /if %}

## Configure The Grid

{% if isFramework("javascript") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

To use Grid Options, simply add the relevant property to the Grid Options object. Let's try this by adding `pagination: true` to our Grid Options:

```jsx
const gridOptions: GridOptions = {
 pagination: true
 // ...
}
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._

***
{% /if %}

{% if isFramework("react") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

Grid Options are passed to the grid component directly as props. Let's enable pagination by adding `pagination={true}`:

```jsx
<div className="ag-theme-quartz" style={{ width: 600, height: 500 }}>
 <AgGridReact
   // ...
   pagination={true} // Enable Pagination
 />
</div>
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._

***
{% /if %}

{% if isFramework("angular") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

Grid Options are passed to the grid via attributes on the `ag-grid-angular` component. Let's enable pagination by adding `[pagination]="true"`:

```html
<!-- The AG Grid component, with various Grid Option properties -->
<ag-grid-angular
 ...
 [pagination]="true"
>
</ag-grid-angular>
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._

***
{% /if %}

{% if isFramework("vue") %}
<!-- Configure The Grid-->

So far we've covered creating a grid, updating the data within the grid, and configuring columns. This section introduces **Grid Options**, which control functionality that extends across both rows & columns, such as Pagination and Row Selection.

Grid Options are added directly to the `ag-grid-vue` component. Let's test this out by adding the `:pagination="true"` to the grid:

```jsx
const App = {
 name: "App",
 template: 
   `
   <ag-grid-vue
     style="width: 100%; height: 100%"
     class="ag-theme-quartz-dark"
     :columnDefs="colDefs"
     :rowData="rowData"
     :defaultColDef="defaultColDef"
     :pagination="true"
   >
   </ag-grid-vue>
   `,
 //...
}
```

We should now see Pagination has been enabled on the grid:

{% gridExampleRunner title="Grid Options Example" name="grid-options-example"  exampleHeight=550 /%}

_Refer to our detailed [Grid Options](./grid-options/) documentation for a full list of options._

***
{% /if %}

## Format Cell Values

{% if isFramework("javascript") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```jsx
columnDefs: [
 {
   field: "price",
   // Return formatted value
   valueFormatter: (params) => { return '£' + params.value.toLocaleString(); }
 },
],
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_

***
{% /if %}

{% if isFramework("react") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```jsx
const [colDefs] = useState([
 {
   field: "price",
   // Return a formatted string for this column
   valueFormatter: params => { return '£' + params.value.toLocaleString(); }
 },
 // ...
]);
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_

***
{% /if %}

{% if isFramework("angular") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```ts
colDefs: ColDef[] = [
 {
   field: "price",
   valueFormatter: params => { return '£' + params.value.toLocaleString(); } // Format with inline function
 },
 // ...
];
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_

***
{% /if %}

{% if isFramework("vue") %}
<!-- Format Cell Values-->

The data supplied to the grid usually requires some degree of formatting. For basic text formatting we can use **Value Formatters**.

**Value Formatters** are basic functions which take the value of the cell, apply some basic formatting, and return a new value to be displayed by the grid. Let's try this by adding the `valueFormatter` property to our 'price' column and returning the formatted value:

```jsx
const colDefs = ref([
  { field: "price", valueFormatter: (params) => { return '£' + params.value.toLocaleString(); } },
  // ...
]);
```

The grid should now show the formatted value in the 'price' column:

{% gridExampleRunner title="Value Formatter Example" name="value-formatter-example"  exampleHeight=550 /%}

_Note: Read our [Value Formatter](./value-formatters/) page for more information on formatting cell values_
{% /if %}

## Custom Cell Components

{% if isFramework("javascript") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you add custom HTML & JS within cells. To use a Cell Renderer, set the `cellRenderer` prop on a column, with the value as the name of your Cell Renderer.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
class CompanyLogoRenderer {
 eGui;

 // Optional: Params for rendering. The same params that are passed to the cellRenderer function.
 init(params) {
   let companyLogo = document.createElement('img');
   companyLogo.src = `https://www.ag-grid.com/example-assets/space-company-logos/${params.value.toLowerCase()}.png`
   companyLogo.setAttribute('style', 'display: block; width: 25px; height: auto; max-height: 50%; margin-right: 12px; filter: brightness(1.1)');
   let companyName = document.createElement('p');
   companyName.textContent = params.value;
   companyName.setAttribute('style', 'text-overflow: ellipsis; overflow: hidden; white-space: nowrap;');
   this.eGui = document.createElement('span');
   this.eGui.setAttribute('style', 'display: flex; height: 100%; width: 100%; align-items: center')
   this.eGui.appendChild(companyLogo)
   this.eGui.appendChild(companyName)
 }

 // Required: Return the DOM element of the component, this is what the grid puts into the cell
 getGui() {
   return this.eGui;
 }

 // Required: Get the cell to refresh.
 refresh(params) {
   return false
 }
}
```

And then adding `cellRenderer: CompanyLogoRenderer` to the 'company' column definition:

```jsx
columnDefs: [
 {
   field: "company",
   cellRenderer: CompanyLogoRenderer
 },
 // ...
],
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_

***
{% /if %}

{% if isFramework("react") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you to use your own React components within cells. To use a custom component, set the `cellRenderer` prop on a column, with the value as the name of your component.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
// Custom Cell Renderer (Display flags based on cell value)
const CompanyLogoRenderer = ({ value }) => (
 <span style={{ display: "flex", height: "100%", width: "100%", alignItems: "center" }}>{value && <img alt={`${value} Flag`} src={`https://www.ag-grid.com/example-assets/space-company-logos/${value.toLowerCase()}.png`} style={{display: "block", width: "25px", height: "auto", maxHeight: "50%", marginRight: "12px", filter: "brightness(1.1)"}} />}<p style={{ textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }}>{value}</p></span>
);
```

And then adding the `cellRenderer` prop on our 'company' column to use our component:

```jsx
const [colDefs] = useState([
 {
   field: "company",
   // Add component to column via cellRenderer
   cellRenderer: CompanyLogoRenderer
 },
 // ...
]);
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_

***
{% /if %}

{% if isFramework("angular") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you to use your own components within cells. To use a custom component, add the `cellRenderer` prop to a column and set the value to the name of your component.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
// Custom Cell Renderer Component
@Component({
 selector: 'app-company-logo-renderer',
 standalone: true,
 imports: [CommonModule],
 template: `<span *ngIf="value" ><img [alt]="value" [src]="'https://www.ag-grid.com/example-assets/space-company-logos/' + value.toLowerCase() + '.png'" /> <p>{{ value }}</p></span>`,
 styles: ["img {display: block; width: 25px; height: auto; max-height: 50%; margin-right: 12px; filter: brightness(1.2);} span {display: flex; height: 100%; width: 100%; align-items: center} p { text-overflow: ellipsis; overflow: hidden; white-space: nowrap }"]
})

export class CompanyLogoRenderer implements ICellRendererAngularComp {
 // Init Cell Value
 public value!: string;
 agInit(params: ICellRendererParams): void {
   this.value = params.value;
 }

 // Return Cell Value
 refresh(params: ICellRendererParams): boolean {
   this.value = params.value;
   return true;
 }
}
```

And then adding the cellRenderer prop on our 'company' column to use our component:

```ts
colDefs: ColDef[] = [
 {
   field: "company",
   cellRenderer: CompanyLogoRenderer // Render a custom component
 }
 // ...
];
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_

***
{% /if %}

{% if isFramework("vue") %}
<!-- Custom Cell Components-->

**Value Formatters** are useful for basic formatting, but for more advanced use-cases we can use **Cell Renderers** instead.

**Cell Renderers** allow you to use your own components within cells. To use a custom component, set the `cellRenderer` prop on a column, with the value as the name of your component.

Let's try this by creating a new component to display the company logo in the 'company' column:

```jsx
const CompanyLogoRenderer = {
 template:
   `
   <span style="display: flex; height: 100%; width: 100%; align-items: center;">
     <img :src="'https://www.ag-grid.com/example-assets/space-company-logos/' + cellValueLowerCase + '.png'" style="display: block; width: 25px; height: auto; max-height: 50%; margin-right: 12px; filter: brightness(1.1);" />
     <p style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">{{ cellValue }}</p>
   </span>
   `,
 setup(props) {
   const cellValue = props.params.value;
   const cellValueLowerCase = cellValue.toLowerCase();
   return {
     cellValue,
     cellValueLowerCase
   };
 },
};
```

And then adding the `cellRenderer` property to the 'company' column:

```jsx
const App = {
 components: {
   AgGridVue,
   companyLogoRenderer: CompanyLogoRenderer
 },
 setup() {
   const colDefs = ref([
     { field: "company", cellRenderer: "companyLogoRenderer" },
     // ...
   ]);
   // ...
 }
 // ...
}
```

Now, when we run the grid, we should see a company logo next to the name:

{% gridExampleRunner title="Cell Renderer Example" name="cell-renderer-example"  exampleHeight=550 /%}

_Note: Read our [Cell Components](./component-cell-renderer/) page for more information on using custom components in cells_

***
{% /if %}

## Handle Grid Events

{% if isFramework("javascript") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to add the relevant `on[EventName]` property to our Grid Options, and provide a function to handle the event.

Let's try this out by enabling cell editing in our DefaultColDefs with `editable: true` and hooking into the `onCellValueChanged` event to log the new value to the console:

```jsx
const gridOptions = {
 // Configurations applied to all columns
 defaultColDef: {
   editable: true,
   // ...
 },
 // Log new value when cell value changes
 onCellValueChanged: (event) => {
   console.log(`New Cell Value: ${event.value}`)
 }
 // ...
}
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_

***
{% /if %}

{% if isFramework("react") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to use the relevant `on[EventName]` prop on the grid component. Let's try this out by enabling cell editing with `editable: true` and hooking into the `onCellValueChanged` event to log the new value to the console:

```jsx
const defaultColDef = useMemo(() => ({
 editable: true, // Enable editing on all cells
 // ...
}))

<div className="ag-theme-quartz" style={{ width: 600, height: 500 }}>
 <AgGridReact
   // Hook into CellValueChanged event and log value
   onCellValueChanged={event => console.log(`New Cell Value: ${event.value}`)}
   // ...
 />
</div>
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_

***
{% /if %}

{% if isFramework("angular") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to add the relevant event name attribute to the `ag-grid-angular` component.

Let's try this out by enabling cell editing with `editable: true` on the Default Column Definitions:

```ts
// Default Column Definitions: Apply configuration across all columns
defaultColDef: ColDef = {
 editable: true
 // ...
}
```

Next, lets create a function to handle the event:

```jsx
// Handle cell editing event
onCellValueChanged = (event: CellValueChangedEvent) => {
 console.log(`New Cell Value: ${event.value}`)
}
```

Finally, let's add the `gridReady` attribute to the `ag-grid-angular` component, with the value as the function we've just created:

```ts
<!-- The AG Grid component, with various Grid Option properties -->
<ag-grid-angular
 (gridReady)="onGridReady($event)"
 ...
>
</ag-grid-angular>
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_

***
{% /if %}

{% if isFramework("vue") %}
<!-- Handle Grid Events-->

In the last section of this tutorial we're going to hook into events raised by the grid using _**Grid Events**_.

To be notified of when an event is raised by the grid we need to use the relevant `@[event-name]` attribute on the `ag-grid-vue` component. Let's try this out by enabling cell editing with `editable: true` and hooking into the `onCellValueChanged` event to log the new value to the console:

```jsx
const App = {
 template:
   `
   <ag-grid-vue
     ...
     @cell-value-changed="onCellValueChanged"
   >
   </ag-grid-vue>
   `,
 methods: {
   onCellValueChanged(event) {
     console.log(`New Cell Value: ${event.value}`);
   }
 },
 setup() {
   const defaultColDef = ref({
     editable: true,
     // ...
   });
   // ...
 }
 // ...
}
```

Now, when we click on a cell we should be able to edit it and see the new value logged to the console:

{% gridExampleRunner title="Complete Example" name="grid-events-example"  exampleHeight=550 /%}

_Refer to our [Grid Events](./grid-events/) documentation for a full list of events raised by the grid_
{% /if %}

## Test Your Knowledge

{% if isFramework("javascript") %}
<!-- Test Your Knowledge-->

Let's put what you've learned so far into action by modifying the grid:

1) Enable Checkbox Selection on the 'mission' column

   _Hint: `checkboxSelection` is a Column Definition property_

1) Enable multiple row selection

   _Hint: `rowSelection` is a Grid Option property_

1) Log a message to the console when a row selection is changed

   _Hint: `onSelectionChanged` is a Grid Event_

1) Format the Date column using `.toLocaleDateString()`;

   _Hint: Use a `valueFormatter` on the 'Date' column to format its value_

1) Add a Cell Renderer to display [ticks](https://www.ag-grid.com/example-assets/icons/tick-in-circle.png) and [crosses](https://www.ag-grid.com/example-assets/icons/cross-in-circle.png) in place of checkboxes on the 'Successful' column:

   _Hint: Use a `cellRenderer` on the 'successful' column_

Once complete, your grid should look like the example below. If you're stuck, check out the source code to see how its done:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

***
{% /if %}

{% if isFramework("react") %}
<!-- Test Your Knowledge-->

Let's put what you've learned so far into action by modifying the grid:

1) Enable Checkbox Selection on the 'mission' column

   _Hint: `checkboxSelection` is a Column Definition property_

1) Enable multiple row selection

   _Hint: `rowSelection` is a Grid Option property_

1) Log a message to the console when a row selection is changed

   _Hint: `onSelectionChanged` is a Grid Event_

1) Format the Date column using `.toLocaleDateString()`;

   _Hint: Use a `valueFormatter` on the 'Date' column to format its value_

1) Add a Cell Renderer to display [ticks](https://www.ag-grid.com/example-assets/icons/tick-in-circle.png) and [crosses](https://www.ag-grid.com/example-assets/icons/cross-in-circle.png) in place of checkboxes on the 'Successful' column:

   _Hint: Use a `cellRenderer` on the 'successful' column_

Once complete, your grid should look like the example below. If you're stuck, check out the source code to see how its done:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

***
{% /if %}

{% if isFramework("angular") %}
<!-- Test Your Knowledge-->

Let's put what you've learned so far into action by modifying the grid:

1) Enable Checkbox Selection on the 'mission' column

   _Hint: `checkboxSelection` is a Column Definition property_

1) Enable multiple row selection

   _Hint: `rowSelection` is a Grid Option property_

1) Log a message to the console when a row selection is changed

   _Hint: `onSelectionChanged` is a Grid Event_

1) Format the Date column using `.toLocaleDateString()`;

   _Hint: Use a `valueFormatter` on the 'Date' column to format its value_

1) Add a Cell Renderer to display [ticks](https://www.ag-grid.com/example-assets/icons/tick-in-circle.png) and [crosses](https://www.ag-grid.com/example-assets/icons/cross-in-circle.png) in place of checkboxes on the 'Successful' column:

   _Hint: Use a `cellRenderer` on the 'successful' column_

Once complete, your grid should look like the example below. If you're stuck, check out the source code to see how its done:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

***
{% /if %}

{% if isFramework("vue") %}
<!-- Test Your Knowledge-->

Let's put what you've learned so far into action by modifying the grid:

1) Enable Checkbox Selection on the 'mission' column

   _Hint: `checkboxSelection` is a Column Definition property_

1) Enable multiple row selection

   _Hint: `rowSelection` is a Grid Option property_

1) Log a message to the console when a row selection is changed

   _Hint: `onSelectionChanged` is a Grid Event_

1) Format the Date column using `.toLocaleDateString()`;

   _Hint: Use a `valueFormatter` on the 'Date' column to format its value_

1) Add a Cell Renderer to display [ticks](https://www.ag-grid.com/example-assets/icons/tick-in-circle.png) and [crosses](https://www.ag-grid.com/example-assets/icons/cross-in-circle.png) in place of checkboxes on the 'Successful' column:

   _Hint: Use a `cellRenderer` on the 'successful' column_

Once complete, your grid should look like the example below. If you're stuck, check out the source code to see how its done:

{% gridExampleRunner title="Testing Example" name="testing-example"  exampleHeight=550 /%}

***
{% /if %}

## Summary

{% if isFramework("javascript") %}
<!-- Summary-->

Congratulations! You've completed the tutorial and built your first grid. By now, you should be familiar with the key concepts of AG Grid:

- **Row Data:** Your data, in JSON format, that you want the grid to display.

- **Column Definitions:** Define your columns and control column-specific functionality, like sorting and filtering.

- **Default Column Definitions:** Similar to Column Definitions, but applies configurations to all columns.

- **Grid Options:** Configure functionality which extends across the entire grid.

- **Grid Events:** Events raised by the grid, typically as a result of user interaction.

- **Value Formatters:** Functions used for basic text formatting

- **Cell Renderers:** Add your own components to cells
{% /if %}

{% if isFramework("react") %}
<!-- Summary-->

Congratulations! You've completed the tutorial and built your first grid. By now, you should be familiar with the key concepts of AG Grid:

- **Row Data:** Your data, in JSON format, that you want the grid to display.

- **Column Definitions:** Define your columns and control column-specific functionality, like sorting and filtering.

- **Default Column Definitions:** Similar to Column Definitions, but applies configurations to all columns.

- **Grid Options:** Configure functionality which extends across the entire grid.

- **Grid Events:** Events raised by the grid, typically as a result of user interaction.

- **Value Formatters:** Functions used for basic text formatting

- **Cell Renderers:** Add your own components to cells
{% /if %}

{% if isFramework("angular") %}
<!-- Summary-->

Congratulations! You've completed the tutorial and built your first grid. By now, you should be familiar with the key concepts of AG Grid:

- **Row Data:** Your data, in JSON format, that you want the grid to display.

- **Column Definitions:** Define your columns and control column-specific functionality, like sorting and filtering.

- **Default Column Definitions:** Similar to Column Definitions, but applies configurations to all columns.

- **Grid Options:** Configure functionality which extends across the entire grid.

- **Grid Events:** Events raised by the grid, typically as a result of user interaction.

- **Value Formatters:** Functions used for basic text formatting

- **Cell Renderers:** Add your own components to cells
{% /if %}

{% if isFramework("vue") %}
<!-- Summary-->

Congratulations! You've completed the tutorial and built your first grid. By now, you should be familiar with the key concepts of AG Grid:

- **Row Data:** Your data, in JSON format, that you want the grid to display.

- **Column Definitions:** Define your columns and control column-specific functionality, like sorting and filtering.

- **Default Column Definitions:** Similar to Column Definitions, but applies configurations to all columns.

- **Grid Options:** Configure functionality which extends across the entire grid.

- **Grid Events:** Events raised by the grid, typically as a result of user interaction.

- **Value Formatters:** Functions used for basic text formatting

- **Cell Renderers:** Add your own components to cells
{% /if %}

## Next Steps

{% if isFramework("javascript") %}
<!-- Next Steps-->

Browse our guides to dive into specific features of the grid:

- [Theming & Styling](./global-style-customisation/)
- [Testing](./testing/)
- [Security](./security/)
{% /if %}

{% if isFramework("react") %}
<!-- Next Steps-->

Browse our guides to dive into specific features of the grid:

- [Theming & Styling](./global-style-customisation/)
- [Testing](./testing/)
- [Security](./security/)
- [Using Hooks](./react-hooks/)
{% /if %}

{% if isFramework("angular") %}
<!-- Next Steps-->

Browse our guides to dive into specific features of the grid:

- [Theming & Styling](./global-style-customisation/)
- [Testing](./testing/)
- [Security](./security/)
{% /if %}

{% if isFramework("vue") %}
Browse our guides to dive into specific features of the grid:

- [Theming & Styling](./global-style-customisation/)
- [Testing](./testing/)
- [Security](./security/)
{% /if %}
